//
//  tttt.c
//  TOYLanuage
//
//  Created by aron on 2019/9/26.
//  Copyright © 2019 aron. All rights reserved.
//

#include "tttt.h"
#include <string>
#include <vector>
#include <map>
#include <cctype>


enum Token_Type {
    EOF_TOKEN = 0,
    DEF_TOKEN,
    IDENTIFIER_TOKEN,
    NUMERIC_TOKEN
};

FILE *file;

// MARK: - Token Parser

static std::string Identifier_string;
static int Numeric_Val;

static int get_token() {
    static int LastChar = ' ';
    
    while(isspace(LastChar))
        LastChar = fgetc(file);
    
    // 字母开头的标识符，后面可以是数字或者字符
    if(isalpha(LastChar)) {
        Identifier_string = LastChar;
        while(isalnum((LastChar = fgetc(file))))
            Identifier_string += LastChar;
        
        if(Identifier_string == "def") return DEF_TOKEN;
        
        return IDENTIFIER_TOKEN;
    }
    
    // 数字开头的数值Token
    if(isdigit(LastChar)) {
        std::string NumStr;
        do {
            NumStr += LastChar;
            LastChar = fgetc(file);
        }  while(isdigit(LastChar));
        
        Numeric_Val = strtod(NumStr.c_str(), 0);
        return NUMERIC_TOKEN;
    }
    
    // 注释内容
    if(LastChar == '#') {
        do LastChar = fgetc(file);
        while(LastChar != EOF && LastChar != '\n' && LastChar != '\r');
        
        if(LastChar != EOF) return get_token();
    }
    
    if(LastChar == EOF) return EOF_TOKEN;
    
    int ThisChar = LastChar;
    LastChar = fgetc(file);
    return ThisChar;
}

// MARK: - ASTNode Define

namespace {

class BaseAST {
    public :
    virtual ~BaseAST() {};
};

class VariableAST : public BaseAST{
    std::string Var_Name;
    // 定义string对象用作存储变量名
public:
    VariableAST (std::string &name) : Var_Name(name) {}
    //变量AST类的含参构造函数由传入构造函数的字符串初始化
};

class NumericAST : public BaseAST {
    int numeric_val;
    public :
    NumericAST (int val) :numeric_val(val) {}
};


class BinaryAST : public BaseAST {
    std::string Bin_Operator; // 用于存储二元运算符的string对象
    BaseAST *LHS, *RHS; // 用于存储一个二元表达式的LHS和RHS的对象。
    // 由于LHS和RHS二元操作可以是任何类型， 因此用BaseAST对象存储。
public:
    BinaryAST(std::string op, BaseAST *lhs, BaseAST *rhs)
    : Bin_Operator(op), LHS(lhs), RHS(rhs) {}
    // 初始化二元运算符、 二元表达式的LHS和RHS
};

class FunctionDeclAST {
    std::string Func_Name;
    std::vector<std::string> Arguments;
public:
    FunctionDeclAST(const std::string &name, const
                    std::vector<std::string> &args) : Func_Name(name), Arguments(args) {};
};


class FunctionDefnAST {
    FunctionDeclAST *Func_Decl;
    BaseAST* Body;
public:
    FunctionDefnAST(FunctionDeclAST *proto, BaseAST *body) :
    Func_Decl(proto), Body(body) {}
    // MARK: FIXME Function* Codegen();
//    Function* Codegen();
};


class FunctionCallAST : public BaseAST {
    std::string Function_Callee;
    std::vector<BaseAST*> Function_Arguments;
public:
    FunctionCallAST(const std::string &callee, std::vector<BaseAST*>
                    &args):
    Function_Callee(callee), Function_Arguments(args) {}
};
}

// MARK: - Grammer Parser

static BaseAST* Base_Parser();
static BaseAST* expression_parser();

static int Current_token;
/**
 Operator_Precedence用于存储运算符优先级：-< +< /< *
 */
static std::map<char, int> Operator_Precedence;

static int next_token() {
    return Current_token = get_token();
}

/**
 返回已定义的二元运算符的优先级

 @return 优先级
 */
static int getBinOpPrecedence() {
    if(!isascii(Current_token))
        return -1;
    
    int TokPrec = Operator_Precedence[Current_token];
    if(TokPrec <= 0) return -1;
    return TokPrec;
}


/**
 标识符Parser。包括变量引用，函数调用
 变量引用： var1
 函数调用： foo(5, 6);
 @return BaseAST*
 */
static BaseAST* identifier_parser() {
    std::string IdName = Identifier_string;
    
    // 读取下一个Token到Current_token
    next_token();
    
    // 返回变量引用
    if(Current_token != '(') {
        return new VariableAST(IdName);
    }

    // 读取下一个Token到Current_token
    next_token();
    
    // 处理方法调用
    std::vector<BaseAST*> Args;
    if(Current_token != ')') {
        while(1) {
            BaseAST* Arg = expression_parser();
            if(!Arg) return 0;
            Args.push_back(Arg);
            
            if(Current_token == ')') break;
            
            if(Current_token != ',')
                return 0;
            next_token();
        }
    }
    next_token();
    
    return new FunctionCallAST(IdName, Args);
}

static BaseAST *numeric_parser() {
    BaseAST *Result = new NumericAST(Numeric_Val);
    next_token();
    return Result;
}

static BaseAST* paran_parser() {
    next_token();
    BaseAST* V = expression_parser();
    if (!V) return 0;
    
    if(Current_token != ')')
        return 0;
    return V;
}

/**
 binary运算符Parser
 eg.
    x + y * 16;
 @param Old_Prec 优先级
 @param LHS 左侧表达式
 @return BaseAST*
 
 example:
     表达式解析Parser
     表达式 => x + y * 12
     func_defn_parser
     expression_parser
     LHS = Base_Parser => x
     binary_op_parser(0, LHS)
     Operator_Prec = 1 (+)
     binOp = +
     currentToken = y
     RHS = Base_Parser = y
     currentToken = *
     Next_Prec = 3(*)
     (Next_prec > Operator_prec) 优先级更高的表达式，需要递归重新计算RHS值
     RHS = binary_op_parser(Operator_Prec + 1, RHS) => RHS =BinaryAST(*, LHS = y, RHS = 12)
     结果 => 二元表达式BinaryAST(+, LHS = x, RHS = (y * 12))
 */
static BaseAST* binary_op_parser(int Old_Prec, BaseAST *LHS) {
    while(1) {
        int Operator_Prec = getBinOpPrecedence();
        
        if(Operator_Prec < Old_Prec)
            return LHS;
        
        int BinOp = Current_token;
        next_token();
        
        BaseAST* RHS = Base_Parser();
        if(!RHS) return 0;
        
        int Next_Prec = getBinOpPrecedence();
        if(Operator_Prec < Next_Prec) {
            RHS = binary_op_parser(Operator_Prec+1, RHS);
            if(RHS == 0) return 0;
        }
        LHS = new BinaryAST(std::to_string(BinOp), LHS, RHS);
    }
}

static BaseAST* expression_parser() {
    BaseAST *LHS = Base_Parser();
    if(!LHS) return 0;
    return binary_op_parser(0, LHS);
}

/**
 解析函数声明Parser
 eg.
    def foo (x y)
 @return FunctionDeclAST *
 */
static FunctionDeclAST *func_decl_parser() {
    if(Current_token != IDENTIFIER_TOKEN)
        return 0;
    
    std::string FnName = Identifier_string;
    next_token();
    
    if(Current_token != '(')
        return 0;
    
    std::vector<std::string> Function_Argument_Names;
    while(next_token() == IDENTIFIER_TOKEN)
        Function_Argument_Names.push_back(Identifier_string);
    if(Current_token != ')')
        return 0;
    
    next_token();
    
    return new FunctionDeclAST(FnName, Function_Argument_Names);
}


/**
 函数定义Parser
 eg.
    def foo (x y)
    x + y * 16;
 @return FunctionDefnAST*
     {
        FunctionDeclAST *Func_Decl;//函数声明
        BaseAST* Body;//函数体
     }
 */
static FunctionDefnAST *func_defn_parser() {
    next_token();
    FunctionDeclAST *Decl = func_decl_parser();
    if(Decl == 0) return 0;
    
    if(BaseAST* Body = expression_parser())
        return new FunctionDefnAST(Decl, Body);
    return 0;
}

static FunctionDefnAST *top_level_parser() {
    if(BaseAST* E = expression_parser()) {
        FunctionDeclAST *Func_Decl = new FunctionDeclAST("", std::vector<std::string>());
        return new FunctionDefnAST(Func_Decl, E);
    }
    return 0;
}

/**
 初始化优先级
 */
static void init_precedence() {
    Operator_Precedence['-'] = 1;
    Operator_Precedence['+'] = 2;
    Operator_Precedence['/'] = 3;
    Operator_Precedence['*'] = 4;
}


static BaseAST* Base_Parser() {
    switch (Current_token) {
        default: return 0;
        case IDENTIFIER_TOKEN : return identifier_parser();
        case NUMERIC_TOKEN : return numeric_parser();
        case '(' : return paran_parser();
    }
}

static void HandleDefn() {
    if (FunctionDefnAST *F = func_defn_parser()) {
        // MARK: F->Codegen()
//        if(Function* LF = F->Codegen()) {
//        }
    }
    else {
        next_token();
    }
}

static void HandleTopExpression() {
    if(FunctionDefnAST *F = top_level_parser()) {
//        if(Function *LF = F->Codegen()) {
//        }
    }
    else {
        next_token();
    }
}


static void Driver() {
    while(1) {
        switch(Current_token) {
            case EOF_TOKEN : return;
            case ';' : next_token(); break;
            case DEF_TOKEN : HandleDefn(); break;
            default : HandleTopExpression(); break;
        }
    }
}

int main() {
    printf("TOYLanguage start==\n");
    
    init_precedence();
    
    file = fopen("/Users/aron/GitRepo/LLVMLearning/ch2/TOYLanuage/TOYLanuage/TestCode.toy", "r");
    if(file == 0) {
        printf("Could not open file\n");
        exit(1);
        return 0;
    }
    
    // 获取第一个Token
    next_token();
    
    Driver();
    
    return 1;
}
